package com.jg.poiet.csv;

import com.jg.poiet.exception.CsvException;
import org.mozilla.universalchardet.UniversalDetector;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class NiceCsv {

    private List<List<String>> dataList = new ArrayList<>();
    private int maxColumnNum;

    public NiceCsv(List<List<String>> dataList) {
        this.dataList = dataList;
        for (List<String> data : dataList) {
            maxColumnNum = Math.max(this.maxColumnNum, data.size());
        }
    }

    public NiceCsv(String path, String charset) {
        File file = new File(path);
        if (!file.exists()) {
            throw new CsvException("文件不存在！");
        }
        try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(path), charset))){
            String line;
            while ((line = br.readLine()) != null) {
                List<String> lineData = parseLine(line);
                this.maxColumnNum = Math.max(this.maxColumnNum, lineData.size());
                dataList.add(lineData);
            }
        } catch (Exception e) {
            throw new CsvException(e.getMessage());
        }
    }

    public void write(String outPath) {
        this.write(new File(outPath));
    }

    public void write(File file) {
        try {
            FileOutputStream outputStream = new FileOutputStream(file);
            this.write(outputStream);
            outputStream.close();
        } catch (Exception e) {
            throw new CsvException(e);
        }
    }

    public void write(OutputStream stream) {
        try {
            //写入utf-8 bom
            stream.write(new byte[]{(byte)0xEF, (byte) 0xBB, (byte) 0xBF});
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stream, "UTF-8"));
            for (List<String> data : this.dataList) {
                StringBuilder line = new StringBuilder();
                for (String str : data) {
                    line.append("\"");
                    if (str != null) {
                        for (char c : str.toCharArray()) {
                            line.append(c);
                            if (c == '"') {
                                line.append(c);
                            }
                        }
                    }
                    line.append("\"");
                    line.append(",");
                }
                if (line.length() > 0) {
                    line.deleteCharAt(line.length() - 1);
                }
                writer.write(line.toString());
                writer.newLine();
            }
            writer.flush();
            writer.close();
        } catch (Exception e) {
            throw new CsvException(e);
        }
    }

    public static NiceCsv compile(String path) {
        //获取文件编码
        UniversalDetector detector = new UniversalDetector(null);
        String encoding = null;
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path))) {
            byte[] buf = new byte[4096];
            int n;
            while ((n = bis.read(buf)) > 0 && !detector.isDone()) {
                detector.handleData(buf, 0, n);
            }
            detector.dataEnd();
            encoding = detector.getDetectedCharset();
        } catch (Exception ignore) {
        } finally {
            detector.reset();
        }
        if (encoding == null) {
            encoding = "utf-8";
        }
        return new NiceCsv(path, encoding);
    }

    /**
     * 转换成html格式
     */
    public String toHtml() {
        StringBuilder res = new StringBuilder();
        res.append("<html>");
        res.append("<head>");
        res.append("<style>");
        res.append(".sheetTitle { font-size: 18px;font-weight: bold;text-align: center;line-height: 40px; }");
        res.append(".tableContainer { max-width: 100%;overflow: auto;padding: 8px; }");
        res.append("table { border-collapse: collapse; }");
        res.append("td { margin: 0; padding: 4px 8px;border: 1px solid black;font-size: 14px; }");
        res.append(".tdDiv { min-height: 20px;min-width: 80px; }");
        res.append("</style>");
        res.append("</head>");
        res.append("<body>");
        res.append("<div class=\"tableContainer\">");
        res.append("<table border=\"0\"><tbody>");
        for (List<String> data : this.dataList) {
                res.append("<tr>");
            for (int i = 0; i < maxColumnNum; i++) {
                String str = "";
                if (i < data.size()) {
                    str = data.get(i);
                }
                res.append("<td>")
                        .append("<div class=\"tdDiv\">")
                        .append(str)
                        .append("</div>")
                        .append("</td>");
            }
            res.append("</tr>");
        }
        res.append("</tbody></table>");
        res.append("</div>");
        res.append("</body>");
        res.append("</html>");
        return res.toString();
    }

    private List<String> parseLine(String line) {
        List<String> res = new ArrayList<>();
        char[] lineChar = line.toCharArray();
        StringBuilder sb = new StringBuilder();
        //是否存在分号
        boolean haveSemicolon = false;
        for (int i = 0; i < lineChar.length; i++) {
            char c = lineChar[i];
            if (sb.length() == 0 && !haveSemicolon) {
                if (c == '"') {
                    haveSemicolon = true;
                } else if (c == ',') {
                    res.add("");
                    haveSemicolon = false;
                } else {
                    haveSemicolon = false;
                    sb.append(c);
                }
            } else {
                if (haveSemicolon) {
                    if (c == '"') {
                        if (i == lineChar.length - 1 || lineChar[i + 1] == ',') {
                            res.add(sb.toString());
                            haveSemicolon = false;
                            sb.delete(0, sb.length());
                        } else if (lineChar[i + 1] == '"') {
                            sb.append(c);
                        } else {
                            throw new CsvException("解析异常！");
                        }
                        i++;
                    } else {
                        sb.append(c);
                    }
                } else {
                    if (c == ',') {
                        res.add(sb.toString());
                        haveSemicolon = false;
                        sb.delete(0, sb.length());
                    } else {
                        sb.append(c);
                    }
                }
            }
        }
        if (sb.length() > 0) {
            res.add(sb.toString());
        }
        return res;
    }

    public List<List<String>> getDataList() {
        return dataList;
    }
}
